package com.qzl.common.netty.protocol;

import cn.hutool.json.JSONUtil;
import com.qzl.common.common.RespConstant;
import com.qzl.common.exception.ChatException;
import com.qzl.common.netty.annotation.MessageType;
import com.qzl.common.netty.config.ChatConfig;
import com.qzl.common.netty.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;

/**
 * @author: qzl
 * @date : 2025/6/23 10:42
 * @description: 自定义消息编解码器
 */
@Slf4j
public class MessageCodec extends ByteToMessageCodec<Object> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
        log.info("开始编码:{}", msg);
        // 文件类消息
        if (msg instanceof Message) {
            Message message = (Message) msg;
            // 文件类型消息
            if (message.getMessageType() == ChatConfig.FILE_MESSAGE) {
                byte[] fileNameBytes = message.getFileName().getBytes(ChatConfig.CHARSET);
                byte[] data = message.getData();
                writeHeader(out, message.getMessageType(), message.getSequenceId(), data.length);
                out.writeInt(fileNameBytes.length);
                out.writeBytes(fileNameBytes);
                out.writeLong(message.getOffset());
                out.writeBytes(data);
                out.writeBoolean(message.isEndOfFile());
            } else {
                // 文本类消息
                int messageType = message.getMessageType();
                String messageJson = JSONUtil.toJsonStr(message);
                byte[] contentBytes = messageJson.getBytes(StandardCharsets.UTF_8);
                writeHeader(out, messageType, message.getSequenceId(), contentBytes.length);
                out.writeBytes(contentBytes);
            }

        } else {
            ctx.fireExceptionCaught(new ChatException(RespConstant.MESSAGE_TYPE_ERROR));
        }
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        log.info("开始解码:{}", in);
        if (in.readableBytes() < 18) {
            log.info("数据长度不足18字节,协议不正确");
            ctx.fireExceptionCaught(new ChatException(RespConstant.MESSAGE_LENGTH_ERROR));
            return;
        }
        byte[] magic = new byte[4];
        in.readBytes(magic);
        if (!(magic[0] == ChatConfig.MAGIC[0]) || !(magic[1] == ChatConfig.MAGIC[1]) || !(magic[2] == ChatConfig.MAGIC[2]) || !(magic[3] == ChatConfig.MAGIC[3])) {
            log.info("协议不正确");
            ctx.fireExceptionCaught(new ChatException(RespConstant.PROTOCOL_ERROR));
            return;
        }
        byte version = in.readByte();
        if (version != ChatConfig.VERSION) {
            log.info("版本不正确");
            ctx.fireExceptionCaught(new ChatException(RespConstant.VERSION_ERROR));
            return;
        }
        // 消息类型
        int messageType = in.readInt();
        // 序列号
        int sequenceId = in.readInt();
        int length = in.readInt();
        if (in.readableBytes() < length) {
            in.resetReaderIndex(); // not enough bytes
            return;
        }
        in.readByte();
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);
        Message message = JSONUtil.toBean(new String(bytes, StandardCharsets.UTF_8), Message.class);
        out.add(message);
    }

    public static void writeHeader(ByteBuf buf, int messageType, int sequenceId, int length) {
        // 魔术 4
        buf.writeBytes(ChatConfig.MAGIC);
        // 版本 1
        buf.writeByte(ChatConfig.VERSION);
        // 消息类型 4
        buf.writeInt(messageType);
        // 序列号 4
        buf.writeInt(sequenceId);
        // 长度 4
        buf.writeInt(length);
        buf.writeByte(0xff);
    }

}
